package com.sunwayworld.baseline.qywx.login;

import com.alibaba.fastjson.JSONObject;
import com.sunwayworld.baseline.qywx.login.bean.AppInfo;
import com.sunwayworld.baseline.qywx.login.bean.EnterpriseWxConf;
import com.sunwayworld.baseline.qywx.login.utils.DateUtil;
import com.sunwayworld.baseline.qywx.login.utils.RestUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 
 * @author Fu Hong Xu
 * @since 2021-09-10
 *
 */


public abstract class QywxSenderService {
    private static final Logger log = LogManager.getLogger(QywxSenderService.class);

    private String accessToken;
    private Date lastAccessTokenDate = null;

    @Autowired
    @Lazy
    private RestTemplate restTemplate;
    
/**
     * 
     * @param url
     * @param req 请求参数
     * @param resClazz 返回值类型
     * @return
     */


    public Map<String, Object> sendBizRequest(String url, Map<String, Object> req, HttpMethod method) {
        if (StringUtils.isEmpty(accessToken)) {
            login();
        }
        
        Map<String, Object> res = sendRequest(url, req, method);
        if (isAccessTokenExpired(res)) {
            login();
        } else {
            return res;
        }
        return sendRequest(url, req, method);
    }

/**
     * get accessToken
     */


    @SuppressWarnings("unchecked")
    private synchronized void login() {
        if (lastAccessTokenDate != null) {
            Date currentTime = DateUtil.getCurrentTime();
            if ((currentTime.getTime() - lastAccessTokenDate.getTime()) < 1 * 60 * 1000L) {
                return;
            }
        }

        String fileJson = RestUtil.getJsonFromFile("enterprise_wx_conf");
        EnterpriseWxConf conf = JSONObject.parseObject(fileJson, EnterpriseWxConf.class);
        String tokenUrl = conf.getTokenUrl();
        AppInfo appInfo = getAppInfo();
        String corpId = appInfo.getCorpId();
        String appSecret = appInfo.getAppSecret();
        
        String url = String.format(tokenUrl, corpId, appSecret);

        log.info("Get accessToken from qywx, name: " + appInfo.getName());
        Map<String, Object> res = (Map<String, Object>) restTemplate.getForObject(url, Map.class);
        accessToken = (String) res.get("access_token");
        if (StringUtils.isBlank(accessToken)) {
            throw new RuntimeException("Get accessToken from qywx failed, name: " + appInfo.getName() + "res: " + res);
        }
        
        lastAccessTokenDate = DateUtil.getCurrentTime();
    }

    private boolean isAccessTokenExpired(Map<String, Object> res) {
        if (res == null) {
            throw new RuntimeException("Res from qywx is null");
        }
        
        Integer errcode = (Integer) res.get("errcode");
        if (errcode.compareTo(0) == 0) {
            return false;
        }

        String fileJson = RestUtil.getJsonFromFile("enterprise_wx_conf");
        EnterpriseWxConf conf = JSONObject.parseObject(fileJson, EnterpriseWxConf.class);
        List<Integer> accessTokenExpiredCodes = conf.getAccessTokenExpiredCodes();
        if (accessTokenExpiredCodes.contains(errcode)) {
            return true;
        }
        
        if (errcode.compareTo(0) != 0) {
            throw new RuntimeException("Error res from qywx, res:" + res);
        }
        
        return false;
    }
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    protected Map<String, Object> sendRequest(String url, Map<String, Object> req, HttpMethod method) {
        String reqMsg = null;
        if (req != null) {
            reqMsg = JSONObject.toJSONString(req);
        }

        url = StringUtils.replace(url, "{access_token}", accessToken);

        log.info("Request to qxwx, req: " + reqMsg + ", url: " + url);
        
        Map<String, Object> res = null;
        if (HttpMethod.GET == method) {
            res = (Map<String, Object>) restTemplate.getForObject(url, Map.class);
        } else {
            HttpHeaders headers = new HttpHeaders();
            HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(req, headers);
            ResponseEntity<Map> response = restTemplate.postForEntity(url, httpEntity, Map.class);
            res = response.getBody();
        }
        
        return res;
    }
    
    protected abstract AppInfo getAppInfo();
}
